package org.zjt.akka;
import java.util.Optional;
import java.util.concurrent.TimeUnit;

import akka.actor.AbstractActor;
import akka.actor.AbstractActor.Receive;
import akka.actor.ActorRef;
import akka.actor.ActorSystem;
import akka.actor.Props;
import akka.event.Logging;
import akka.event.LoggingAdapter;
import akka.testkit.javadsl.TestKit;
import lombok.extern.slf4j.Slf4j;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;

import static org.junit.Assert.assertEquals;

/**
 * Description:
 *
 * @author juntao.zhang
 * Date: 2018-06-27 下午9:50
 * @see
 */
public class DeviceTest2 {

    @Slf4j
    public static class Device extends AbstractActor {


        final String groupId;

        final String deviceId;

        public Device(String groupId, String deviceId) {
            this.groupId = groupId;
            this.deviceId = deviceId;
        }

        public static Props props(String groupId, String deviceId) {
            return Props.create(Device.class, groupId, deviceId);
        }

        public static final class RecordTemperature {
            final long requestId;
            final double value;

            public RecordTemperature(long requestId, double value) {
                this.requestId = requestId;
                this.value = value;
            }
        }

        public static final class TemperatureRecorded {
            final long requestId;

            public TemperatureRecorded(long requestId) {
                this.requestId = requestId;
            }
        }

        public static final class ReadTemperature {
            final long requestId;

            public ReadTemperature(long requestId) {
                this.requestId = requestId;
            }
        }

        public static final class RespondTemperature {
            final long requestId;
            final Optional<Double> value;

            public RespondTemperature(long requestId, Optional<Double> value) {
                this.requestId = requestId;
                this.value = value;
            }
        }

        Optional<Double> lastTemperatureReading = Optional.empty();

        @Override
        public void preStart() {
            log.info("Device actor {}-{} started", groupId, deviceId);
        }

        @Override
        public void postStop() {
            log.info("Device actor {}-{} stopped", groupId, deviceId);
        }

        @Override
        public Receive createReceive() {
            return receiveBuilder()
                    .match(RecordTemperature.class, r -> {
                        log.info("Recorded temperature reading {} with {}", r.value, r.requestId);
                        log.info("Recorded 在增加 Device 设置属性 lastTemperatureReading，并给调用者发送反馈消息");
                        lastTemperatureReading = Optional.of(r.value);
                        getSender().tell(new TemperatureRecorded(r.requestId), getSelf());
                    })
                    .match(ReadTemperature.class, r -> {
                        log.info("Read Device 的 lastTemperatureReading 属性，并发送给发送者（调用者）");
                        getSender().tell(new RespondTemperature(r.requestId, lastTemperatureReading), getSelf());
                    })
                    .build();
        }
    }


    ActorSystem system ;

    @Before
    public void startup() {
        system = ActorSystem.create("testSystem");
    }



    @After
    public void shutdown() throws InterruptedException {
        TimeUnit.SECONDS.sleep(20);
        system.terminate();
    }


    @Test
    public void testReplyWithLatestTemperatureReading() {
        TestKit probe = new TestKit(system);
        ActorRef deviceActor = system.actorOf(Device.props("group", "device"));

        /** 1、发送record数据 **/
        deviceActor.tell(new Device.RecordTemperature(1L, 24.0), probe.getRef());
        assertEquals(1L, probe.expectMsgClass(Device.TemperatureRecorded.class).requestId);

        /** 1、发送read数据，得到record信息 **/
        deviceActor.tell(new Device.ReadTemperature(2L), probe.getRef());
        Device.RespondTemperature response1 = probe.expectMsgClass(Device.RespondTemperature.class);
        assertEquals(2L, response1.requestId);
        assertEquals(Optional.of(24.0), response1.value);


        /** 2、发送record数据 **/
        deviceActor.tell(new Device.RecordTemperature(3L, 55.0), probe.getRef());
        assertEquals(3L, probe.expectMsgClass(Device.TemperatureRecorded.class).requestId);

        /** 2、发送read数据，得到record信息 **/
        deviceActor.tell(new Device.ReadTemperature(4L), probe.getRef());
        Device.RespondTemperature response2 = probe.expectMsgClass(Device.RespondTemperature.class);
        assertEquals(4L, response2.requestId);
        assertEquals(Optional.of(55.0), response2.value);
    }
}
